home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
hity wydania
/
Ubuntu 9.10 PL
/
karmelkowy-koliberek-desktop-9.10-i386-PL.iso
/
casper
/
filesystem.squashfs
/
usr
/
bin
/
foomatic-printjob
< prev
next >
Wrap
Text File
|
2009-09-18
|
35KB
|
1,171 lines
#!/usr/bin/perl
# -*- perl -*-
# This is foomatic-printjob, a program to print and manage printing
# jobs with the same commands independent whether the spooler is CUPS,
# LPD, LPRng, or PDQ.
# It also comprises half of a programattic API for user tools: you can
# learn and control everything about the properties of printing jobs
# here. With the sister program foomatic-configure, you can do
# everything related to print queue static state: install, modify,
# remove queues, query queue, printer, and driver info.
use Foomatic::Defaults;
use Foomatic::DB;
# Read out the program name with which we were called, but discard the path
$0 =~ m!/([^/]+)\s*$!;
$progname = $1;
# We use the library Getopt::Long here, so that we can have more than one "-o"
# option on one command line.
use Getopt::Long;
Getopt::Long::Configure("no_ignore_case", "pass_through");
GetOptions("P=s" => \$opt_P, # which queue (Printer)?
"d=s" => \$opt_d, # which queue (Destination)?
"s=s" => \$opt_s, # which Spooler?
"o=s" => \@opt_o, # printing Options
"Q" => \$opt_Q, # Query jobs in queue
"R" => \$opt_R, # Remove job(s)
"C" => \$opt_C, # Control job(s)/queue(s)
"S" => \$opt_S, # set default Spooler
"h" => \$opt_h); # Help!
help() if ($opt_h && !$opt_P);
my $db = new Foomatic::DB;
my $in_config = {'queue' => $opt_P,
'options' => \@opt_o,
'spooler' => $opt_s};
# Default action: Printing
my $action = 'print';
# Determine the action by the name how we were called
if ($progname =~ m!^lpc!) { # 'lpc*' ==> control
$action = 'control';
} elsif ($progname =~ m!^lprm!) { # 'lprm*' ==> remove jobs
$action = 'remove';
} elsif ($progname =~ m!^lpq!) { # 'lpq*' ==> list jobs
$action = 'query';
} elsif (($progname =~ m!^lpr!) || ($progname =~ m!^lp!)) {
# 'lpr*', 'lp*' ==> print
$action = 'print';
}
# Determine the action by a command line option
$action = ($opt_R ? 'remove' : $action);
$action = ($opt_Q ? 'query' : $action);
$action = ($opt_C ? 'control' : $action);
my $procs = { 'lpd' => { 'print' => \&print_lpd,
'query' => \&query_lpd,
'remove' => \&remove_lpd,
'control' => \&control_lpd },
'lprng'=>{ 'print' => \&print_lprng,
'query' => \&query_lprng,
'remove' => \&remove_lprng,
'control' => \&control_lpd },
'cups' =>{ 'print' => \&print_cups,
'query' => \&query_cups,
'remove' => \&remove_cups,
'control' => \&control_cups },
'pdq' =>{ 'print' => \&print_pdq,
'query' => \&query_pdq,
'remove' => \&remove_pdq,
'control' => \&control_pdq } };
if (!(defined($in_config->{'queue'}))) {
# No job handling without knowing the name of the queue
# PRINTER environment variable
if (defined($opt_d)) {
$in_config->{'queue'} = $opt_d;
} elsif (defined($ENV{PRINTER})) {
$in_config->{'queue'} = $ENV{PRINTER};
} else {
# Use spoolers default
}
}
if (!defined($in_config->{'spooler'})) {
# Personal default spooler
if (($> != 0) && (-f "$ENV{'HOME'}/.defaultspooler")) {
$s = `cat $ENV{'HOME'}/.defaultspooler`;
chomp $s;
}
# System default spooler
if ((!defined($s)) && (-f "$sysdeps->{'foo-etc'}/defaultspooler")) {
$s = `cat $sysdeps->{'foo-etc'}/defaultspooler`;
chomp $s;
}
if (!defined($s)) {
$s = detect_spooler();
}
die "Unable to identify spooler, please specify one with \"-s\"!\n"
unless $s;
if (defined($opt_i)) {
print STDERR "You appear to be using $s. Correct? ";
my $yn = <STDIN>;
die "\n" if ($yn !~ m!^y!i);
}
$in_config->{'spooler'} = $s;
}
if (defined($opt_S)) {
if ($> == 0) { # Program invoked as "root"?
# Set system default spooler
open DEFAULTFILE, "> $sysdeps->{'foo-etc'}/defaultspooler" ||
die "Cannot write $sysdeps->{'foo-etc'}/defaultspooler!\n";
print DEFAULTFILE "$in_config->{'spooler'}\n";
close DEFAULTFILE;
exit 0;
} else {
# Set personal default spooler
open DEFAULTFILE, "> $ENV{'HOME'}/.defaultspooler" ||
die "Cannot write $ENV{'HOME'}/.defaultspooler!\n";
print DEFAULTFILE "$in_config->{'spooler'}\n";
close DEFAULTFILE;
exit 0;
}
}
# Exception...
help_options($in_config) if ($opt_h);
# Call proper proc
exit &{$procs->{$in_config->{'spooler'}}{$action}}($in_config);
### Printing/Job manipulation functions for LPD
sub print_lpd {
my ($config) = $_[0];
#sysdeps->{'lpd-lpr'} = "/home/test/lpr-0.71/lpr/lpr";
# Auto-detect whether the "lpr" executable is the VA-Linux version or not
my $valinuxlpr =
!(system "strings $sysdeps->{'lpd-lpr'} | grep option > /dev/null");
# Printing command
my $commandline = "$sysdeps->{'lpd-lpr'}";
# Add the printer queue argument
if (defined($config->{'queue'})) {
$commandline .= " -P $config->{'queue'}";
}
# Add the driver-specific options supplied by the user, if any
# For the VA-Linux implementation of "lpr" (gnulpr) options are passed
# with '-o option=value -o switch', for the BSD implementation they are
# passe with '-J"option=value switch"'.
if ($valinuxlpr) {
# VA-Linux/gnulpr
if ($#{$config->{'options'}} >= 0) {
for (@{$config->{'options'}}) {
$commandline .= " -o $_";
}
}
} else {
# BSD
if ($#{$config->{'options'}} >= 0) {
$commandline .= " -J\"";
for (@{$config->{'options'}}) {
$commandline .= "$_ ";
}
$commandline .= "\"";
}
}
# Add the remaining command line arguments, they are the names of
# the files to print and also spooler-specific options
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n";
return (system $commandline) >> 8;
}
sub query_lpd {
my ($config) = $_[0];
# standard lpq, emulate -a of lpq-cups
# Read additional options
GetOptions("a" => \$opt_a); # List jobs on all printers
if (defined($opt_a)) {
# Get all printer queues
open QUEUELIST, "$sysdeps->{'lpd-lpc'} status 2>&1 | grep \":\$\" | ";
my @queuelist = <QUEUELIST>;
close QUEUELIST;
# List the jobs on all the queues
for (@queuelist) {
my $queue = $_;
chomp $queue;
print "$queue\n";
$queue =~ s/:$//;
my $result = (system "$sysdeps->{'lpd-lpq'} -P $queue @ARGV") >> 8;
if ($result != 0) {return $result};
}
} else {
# List the jobs on the specified queue
my $queue = "";
if (defined($config->{'queue'})) {
$queue = " -P $config->{'queue'}";
}
return (system "$sysdeps->{'lpd-lpq'}$queue @ARGV") >> 8;
}
}
sub remove_lpd {
my ($config) = $_[0];
# Remove a job with the standard "lprm" command
# Removing command
my $commandline = "$sysdeps->{'lpd-lprm'}";
# Add the printer queue argument
if (defined($config->{'queue'})) {
$commandline .= " -P $config->{'queue'}";
}
# Add the remaining command line arguments, they are the numbers
# of the jobs to kill, the users whose jos to remove and also
# spooler-specific options
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n";
return (system $commandline) >> 8;
}
sub control_lpd {
my ($config) = $_[0];
# Control the printing system with the standard "lpc" command
# Control command
my $commandline = "$sysdeps->{'lpd-lpc'}";
# Add the remaining command line arguments, they are the control command
# with its arguments
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n";
return (system $commandline) >> 8;
}
### Printing/Job manipulation functions for LPRng
sub print_lprng {
my ($config) = $_[0];
# Printing command
my $commandline = "$sysdeps->{'lpd-lpr'}";
# Add the printer queue argument
if (defined($config->{'queue'})) {
$commandline .= " -P $config->{'queue'}";
}
# Add the driver-specific options supplied by the user, if any
if ($#{$config->{'options'}} >= 0) {
for (@{$config->{'options'}}) {
$commandline .= " -Z $_";
}
}
# Add the remaining command line arguments, they are the names of
# the files to print and also spooler-specific options
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n";
return (system $commandline) >> 8;
}
sub query_lprng {
my ($config) = $_[0];
# We filter the output of lpq and rearrange it to have the same format
# as of LPD and CUPS.
GetOptions("l" => \$opt_l); # Long, more verbose output
# List the jobs on the specified queue
my $queue = "";
if (defined($config->{'queue'})) {
$queue = " -P $config->{'queue'}";
}
open LPQOUTPUT, "$sysdeps->{'lpd-lpq'}$queue @ARGV |" || return 1;
my @lpqoutput = <LPQOUTPUT>;
close LPQOUTPUT;
# Filter the output
for $line (@lpqoutput) {
chomp $line;
if ($line =~ m!^\s*(\S+)\s+([^@\s]+)@[^@\+\s]+\+[0-9]+\s+\S+\s+([0-9]+)\s+(\S+)\s+([0-9]+)\s+[0-9:]+\s*$!) {
my ($rank, $owner, $jobid, $file, $size) = ($1, $2, $3, $4, $5);
if (defined($opt_l)) {
my $owner_rank = "$owner: $rank";
if (length($owner_rank) > 40) {
$owner_rank = substr($owner_rank, 0, 40);
}
if (length($file) > 40) {$file = substr($file, 0, 40);}
print sprintf("\n%-40s [job %d]\n\t%-40s %d bytes\n",
$owner_rank, $jobid, $file, $size);
} else {
if (length($rank) > 6) {$rank = substr($rank, 0, 6)};
if (length($owner) > 8) {$owner = substr($owner, 0, 8)};
if (length($file) > 37) {$file = substr($file, 0, 37)};
print sprintf("%-6s %-8s % 6d %-37s %d bytes\n",
$rank, $owner, $jobid, $file, $size);
}
} elsif ($line =~ m!\s*Rank\s+Owner!) {
if (!defined($opt_l)) {
print "Rank Owner Job File(s) Total Size\n";
}
} else {
print("$line\n");
}
}
}
sub remove_lprng {
my ($config) = $_[0];
# Remove a job with the standard "lprm" command and emulate the "-"
# option of the lprm command of BSD LPD
# Removing command
my $commandline = "$sysdeps->{'lpd-lprm'}";
# Add the printer queue argument
if (defined($config->{'queue'})) {
$commandline .= " -P $config->{'queue'}";
}
# Replace the "-" option by the "all" option
my $alljobs = "";
for ($i = 0; ($i <= $#ARGV); $i++) {
if ($ARGV[$i] =~ m!^\s*\-\s*$!) {
$alljobs = " all";
splice(@ARGV,$i,1);
$i--;
}
}
$commandline .= $alljobs;
# Add the remaining command line arguments, they are the numbers
# of the jobs to kill, the users whose jos to remove and also
# spooler-specific options
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n";
return (system $commandline) >> 8;
}
sub control_lprng {
# The lpc command of lprng is compatible to the one of LPD, it has only
# many more commands. So we use the "control_lpd" function also for
# lprng.
}
### Printing/Job manipulation functions for CUPS
sub print_cups {
my ($config) = $_[0];
# Printing command
my $commandline = "$sysdeps->{'cups-lpr'}";
# Add the printer queue argument
if (defined($config->{'queue'})) {
$commandline .= " -P $config->{'queue'}";
}
# Add the driver-specific options supplied by the user, if any
if ($#{$config->{'options'}} >= 0) {
for (@{$config->{'options'}}) {
$commandline .= " -o $_";
}
}
# Add the remaining command line arguments, they are the names of
# the files to print and also spooler-specific options
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n";
return (system $commandline) >> 8;
}
sub query_cups {
my ($config) = $_[0];
# List the jobs on the specified queue
my $queue = "";
if (defined($config->{'queue'})) {
$queue = " -P $config->{'queue'}";
}
return (system "$sysdeps->{'cups-lpq'}$queue @ARGV") >> 8;
}
sub remove_cups {
my ($config) = $_[0];
# Remove a job with the standard "lprm" command
# Removing command
my $commandline = "$sysdeps->{'cups-lprm'}";
# Add the printer queue argument
if (defined($config->{'queue'})) {
$commandline .= " -P $config->{'queue'}";
}
# Add the remaining command line arguments, they are the numbers
# of the jobs to kill, the users whose jos to remove and also
# spooler-specific options
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n";
return (system $commandline) >> 8;
}
sub control_cups {
my ($config) = $_[0];
# CUPS has no LPD/LPRng-compatible lpc command, so we must emulate
# this functionality with the command line tools of CUPS.
# The first command line argument (of the remaining ones) is the
# control command (standard commands of lpc for LPD/LPRng)
my $command = shift (@ARGV);
if (!defined($command)) {
die "You must supply a control command with the \"-C\" option!\n";
} elsif (lc($command) eq "up") { # Turn on queue (queueing/printing)
return (system "$sysdeps->{'cups-enable'} @ARGV; $sysdeps->{'cups-accept'} @ARGV") >> 8;
} elsif (lc($command) eq "down") { # Turn off queue (queueing/printing)
return (system "$sysdeps->{'cups-disable'} @ARGV; $sysdeps->{'cups-reject'} @ARGV") >> 8;
} elsif (lc($command) eq "start") { # Turn on queue (printing)
return (system "$sysdeps->{'cups-enable'} @ARGV") >> 8;
} elsif (lc($command) eq "stop") { # Turn off queue (printing)
return (system "$sysdeps->{'cups-disable'} @ARGV") >> 8;
} elsif (lc($command) eq "enable") { # Accept new jobs
return (system "$sysdeps->{'cups-accept'} @ARGV") >> 8;
} elsif (lc($command) eq "disable") { # Reject new jobs
return (system "$sysdeps->{'cups-reject'} @ARGV") >> 8;
} elsif (lc($command) eq "move") { # Move jobs
if (($#ARGV < 1) or ($#ARGV > 2)) {
die "Usage of the \"move\" control command:\n\n move oldqueue [ jobID ] newqueue\n\n";
}
# The first argument is always the source printer
my $fromqueue = shift (@ARGV);
# The second argument is the job ID or the destination
my $jobid = shift (@ARGV);
# The third argument is the destination
my $toqueue = shift (@ARGV);
if (!defined($toqueue)) {
# No job ID given, move all jobs in the given queue
$toqueue = $jobid;
open LINES, "$sysdeps->{'cups-lpq'} -P $fromqueue |";
my @lines = <LINES>;
close LINES;
for (@lines) {
if ($_ =~ m!^\s*\S+\s+\S+\s+([0-9]+)\s+!) {
system "$sysdeps->{'cups-lpmove'} $fromqueue-$1 $toqueue";
}
}
return;
} else {
# Treat the specified job
return (system "$sysdeps->{'cups-lpmove'} $fromqueue-$jobid $toqueue") >> 8;
}
} elsif ((lc($command) eq "hold") || # Hold job
(lc($command) eq "release") || # Resume job
(lc($command) eq "topq")) { # Bring job to the top of the
# queue
if (($#ARGV < 0) or ($#ARGV > 1)) {
die "Usage of the \"$command\" control command:\n\n $command queue [ jobID ] \n\n";
}
# Clean up the command
$command = lc($command);
if ($command eq "release") {$command = "resume";}
if ($command eq "topq") {$command = "immediate";}
# The first argument is always the queue
my $queue = shift (@ARGV);
# The second argument is the job ID
my $jobid = shift (@ARGV);
if (!defined($jobid)) {
# No job ID given, treat all jobs in the given queue
open LINES, "$sysdeps->{'cups-lpq'} -P $queue |";
my @lines = <LINES>;
close LINES;
for (@lines) {
if ($_ =~ m!^\s*\S+\s+\S+\s+([0-9]+)\s+!) {
system "$sysdeps->{'cups-lp'} -i $queue-$1 -H $command";
}
}
return;
} else {
# Treat the specified job
return (system "$sysdeps->{'cups-lp'} -i $queue-$jobid -H $command") >> 8;
}
} elsif (lc($command) eq "status") { # Queue status listing
return (system "$sysdeps->{'cups-lpc'} status @ARGV") >> 8;
} elsif (lc($command) eq "help") { # List the available commands
print "The following control commands are available:\n\n";
print " up queue : Turn on queue (queueing/printing)\n";
print " down queue : Turn off queue (queueing/printing)\n";
print " start queue : Turn on printing on queue\n";
print " stop queue : Turn off printing on queue\n";
print " enable queue : Make queue accepting new jobs\n";
print " disable queue : Make queue rejecting new jobs\n";
print " move oldqueue [ jobid ] newqueue : \n";
print " Move job jobid in oldqueue to newqueue\n";
print " Move all jobs in oldqueue to newqueue when jobid not given\n";
print " hold queue [ jobid ] : Hold job jobid or all jobs in queue\n";
print " release queue [ jobid ] : Release job jobid or all jobs in queue\n";
print " topq queue jobid : Print job jobid in queue immediately\n";
print " status [ queue ] : Status of queue or of all queues\n";
print " help : This help message\n\n";
} else {
die "Command \"$command\" not recognized!\n";
}
}
### Printing/Job manipulation functions for PDQ
sub print_pdq {
my ($config) = $_[0];
# Printing command
my $commandline = "$sysdeps->{'pdq-print'}";
# Add the printer queue argument
if (defined($config->{'queue'})) {
$commandline .= " -P $config->{'queue'}";
}
# Add the driver-specific options supplied by the user, if any
if ($#{$config->{'options'}} >= 0) {
for (@{$config->{'options'}}) {
my $option = $_;
if ($option =~ m!^\s*([^=]+=[\+\-0-9\.]+)\s*$!) {
# Foomatic treats numerical options as PDQ arguments ("-a"),
# but there can be enumerated options with numbers as choices,
# so we give the option in both styles. Since PDQ silently
# ignores non-existent options, the wrong form of the option
# will be ignored.
$commandline .= " -aOPT_$1";
}
# Enumerated and boolean options are PDQ options ("-o"),
# the "=" has to be replaced by "_" to work with the
# PDQ-O-MATIC-generated configuration
$option =~ s/=/_/; # Replace only the first "="
$commandline .= " -o$option";
}
}
# The "-#" option for multiple copies is not supported by the print
# command "pdq". So we launch "pdq" once per copy. Thw command line
# will be modified appropriately directly before the printing command
# is launched.
# Note: '#' as option name is not supported by the Perl library
# Getopt::Long.
my $num_copies = 1;
my $file_in_args = 0;
my $i;
for ($i = 0; ($i <= $#ARGV); $i++) {
if ($ARGV[$i] =~ m!^\s*\-\#\s*([0-9]+)\s*$!) {
$num_copies = $1;
splice(@ARGV,$i,1);
$i--;
} elsif ($ARGV[$i] =~ m!^\s*\-\#\s*$!) {
if ((defined $ARGV[$i+1]) &&
($ARGV[$i+1] =~ m!^\s*([0-9]+)\s*$!)) {
$num_copies = $1;
splice(@ARGV,$i,2);
$i--;
}
} elsif ($ARGV[$i] =~ m!^\s*[^\-]+!) {
$file_in_args = 1;
}
}
# Add the remaining command line arguments, they are the names of
# the files to print and also spooler-specific options
$commandline .= " @ARGV";
# Do it!
#print "$commandline\n"; return 0;
if ($num_copies == 1) {
return (system $commandline) >> 8;
} else {
if ($file_in_args == 0) {
# We print from standard input, so we must buffer it to be able
# to print multiple copies
my @job_contents = <STDIN>;
my $i;
for ($i = 0; $i < $num_copies; $i++) {
open PIPE, "| $commandline" ||
die "Could not launch printing command!\n";
print PIPE @job_contents;
close PIPE;
}
return 0;
} else {
# We print files
my $result = 0;
my $i;
for ($i = 0; $i < $num_copies; $i++) {
$result = (system $commandline) >> 8;
if ($result != 0) {return $result};
}
return 0;
}
}
}
sub query_pdq {
my ($config) = $_[0];
# PDQ has no possiblity to list the printing jobs from the command
# line. So we read the *.status files in ~/.printjobs and generate
# the job entry lines from that information.
# Read additional options
GetOptions("a" => \$opt_a, # List jobs on all printers
"l" => \$opt_l); # Long, more verbose output
# Make sure that a printer is specified when the "-a" option is not
# given
if ((!(defined($opt_a))) && (!(defined($config->{'queue'})))) {
$config->{'queue'} = get_pdq_default_printer();
}
# If the user specified job numbers, list them. User names on the
# command line do not make much sense, because under PDQ a user can
# only see ones own jobs, they are supported here to do not break
# front ends
my $joblist = {};
my $userlist = {};
my $listalljobs = 1;
my $listallusers = 1;
my $i;
for ($i = 0; ($i <= $#ARGV); $i++) {
if ($ARGV[$i] =~ m!^\s*([0-9]+)\s*$!) {
my $job=$1;
# Fill up the number with zeros so that it has three digits
while (length($job) < 3) {$job = "0" . $job;}
$joblist->{$job} = 1;
$listalljobs = 0;
splice(@ARGV,$i,1);
$i--;
} elsif ($ARGV[$i] =~ m!^\s*[^\-]+!) {
my $user=$ARGV[$i];
$userlist->{$user} = 1;
$listallusers = 0;
splice(@ARGV,$i,1);
$i--;
} else {
die "Unknown option: $ARGV[$i]\n";
}
}
# When we list only the jobs for a specific printer, display the
# printer status at first. In PDQ the printer status cannot be
# retrived from the command line, so we put a dummy line
# "<printer> is ready".
if (!(defined($opt_a))) {
if (!pdq_check_printer($config->{'queue'})) {
die "$config->{'queue'}: unknown printer\n";
}
print "$config->{'queue'} is ready\n";
}
# Read in the names of all job status files in ~/.printjobs/
my @jobnumbers = ();
opendir PJDIR, "$ENV{'HOME'}/.printjobs" ||
return 0; # No ~/.printjobs/ directory ==> no jobs
while ($filename = readdir(PJDIR)) {
if ($filename =~ m!^([0-9][0-9][0-9]).status$!) {
push (@jobnumbers, $1);
}
}
close PJDIR;
# Sort the filenames in descending order to get the most recent jobs
# listed at first
@jobnumbers = sort {$b cmp $a} @jobnumbers;
# Now list the jobs
my $firstline = 1;
for ($i = 0; $i <= $#jobnumbers; $i ++) {
# Omit this job if job numbers are specified on the command line, but
# not the one of this job
next if (($listalljobs == 0) &&
(!(defined($joblist->{$jobnumbers[$i]}))));
# Read the job status file
next if !open JOBSTATUSFILE,
"< $ENV{'HOME'}/.printjobs/$jobnumbers[$i].status";
my $jobstatusdata = join("", <JOBSTATUSFILE>);
close JOBSTATUSFILE;
# Extract the important fields from the file
# Status:
my $status = "";
if ($jobstatusdata =~ m!^\s*status\s*\=\s*{([^{}]*)}\s*$!m) {
$status = $1;
}
# Omit this job when it has no status field or when the job is
# already finished, cancelled, or aborted
next if (($status eq "") || ($status =~ m!aborted!) ||
($status =~ m!finished!) || ($status =~ m!cancelled!));
# Avoid spaces in the status field, so that frontends can separate the
# fields from the job list more easily.
$status =~ s/\s//g;
# Printer
my $printer;
if ($jobstatusdata =~ m!^\s*printer\s*\=\s*{([^{}]*)}\s*$!m) {
$printer = $1;
}
# Omit this job when we are querying only the jobs of another printer
next if ((!(defined($opt_a))) && ($printer ne $config->{'queue'}));
# Owner
my $owner;
if ($jobstatusdata =~
m!^\s*env_driver\s*\=\s*{.*\"LOGNAME\"\s*=\s*\"([^\"]*)\".*}\s*$!m) {
$owner = $1;
}
# Omit this job if user names are specified on the command line, but
# not the owner of this job
next if (($listallusers == 0) &&
(!(defined($userlist->{$owner}))));
# File
my $file;
if ($jobstatusdata =~ m!^\s*input_filename\s*\=\s*{([^{}]*)}\s*$!m) {
$file = $1;
}
# Size of job input file
my $size;
if (-f "$ENV{'HOME'}/.printjobs/$jobnumbers[$i].raw") {
$size = (stat("$ENV{'HOME'}/.printjobs/$jobnumbers[$i].raw"))[7];
}
# Now get the info nicely onto the screen
my $outputline;
if ($opt_l) {
# Long (3+ lines per job) mode
my $owner_status = "$owner: $status";
if (length($owner_status) > 40) {
$owner_status = substr($owner_status, 0, 40);
}
if (length($file) > 40) {$file = substr($file, 0, 40);}
$outputline = sprintf("\n%-40s [job %d]\n\t%-40s %d bytes\n",
$owner_status, $jobnumbers[$i], $file,
$size);
} else {
# Short (1 line per job) mode
if ($firstline == 1) {
# headline
print "Rank Owner Job File(s) Total Size\n";
$firstline = 0;
}
if (length($status) > 6) {$status = substr($status, 0, 6);}
if (length($owner) > 10) {$owner = substr($owner, 0, 10);}
if (length($file) > 37) {$file = substr($file, 0, 37);}
$outputline = sprintf("%-6s %-10s % 3d %-37s %d bytes\n",
$status, $owner, $jobnumbers[$i], $file,
$size);
}
print $outputline;
}
# Say "no entries" if no job was listed
if ($firstline == 1) {
print "no entries\n";
}
}
sub remove_pdq {
my ($config) = $_[0];
# PDQ has no possiblity to remove printing jobs from the command
# line. "xpdq" cancels jobs by "touch"ing <job id>.cancelled
# files in ~/.printjobs and setting the permissions of these files
# to 0600.
# Make sure that a printer is specified when the "-a" option is not
# given
if (!(defined($config->{'queue'}))) {
$config->{'queue'} = get_pdq_default_printer();
}
# If the user specified job numbers, list them. User names on the
# command line do not make much sense, because under PDQ a user can
# only see ones own jobs, they are supported here to do not break
# front ends
my $joblist = {};
my $userlist = {};
my $nojob = 1;
my $nouser = 1;
my $opt_alljobs = 0;
my $i;
for ($i = 0; ($i <= $#ARGV); $i++) {
if ($ARGV[$i] =~ m!^\s*([0-9]+)\s*$!) {
my $job=$1;
# Fill up the number with zeros so that it has three digits
while (length($job) < 3) {$job = "0" . $job;}
$joblist->{$job} = 1;
$nojob = 0;
splice(@ARGV,$i,1);
$i--;
} elsif ($ARGV[$i] =~ m!^\s*[^\-]+!) {
my $user=$ARGV[$i];
$userlist->{$user} = 1;
$nouser = 0;
splice(@ARGV,$i,1);
$i--;
} elsif ($ARGV[$i] =~ m!^\s*\-\s*$!) {
$opt_alljobs = 1;
splice(@ARGV,$i,1);
$i--;
} else {
die "Unknown option: $ARGV[$i]\n";
}
}
# Does the chosen printer exist
if (!pdq_check_printer($config->{'queue'})) {
die "$config->{'queue'}: unknown printer\n";
}
# Read in the names of all job status files in ~/.printjobs/
my @jobnumbers = ();
opendir PJDIR, "$ENV{'HOME'}/.printjobs" ||
return 0; # No ~/.printjobs/ directory ==> no jobs
while ($filename = readdir(PJDIR)) {
if ($filename =~ m!^([0-9][0-9][0-9]).status$!) {
push (@jobnumbers, $1);
}
}
close PJDIR;
# Sort the filenames in descending order to get the most recent
# (probably still waiting) jobs removed at first
@jobnumbers = sort {$b cmp $a} @jobnumbers;
# Now search the jobs to remove
my $nothingremoved = 1;
my $mostrecent = 1;
for ($i = 0; $i <= $#jobnumbers; $i ++) {
# Read the job status file
next if !open JOBSTATUSFILE,
"< $ENV{'HOME'}/.printjobs/$jobnumbers[$i].status";
my $jobstatusdata = join("", <JOBSTATUSFILE>);
close JOBSTATUSFILE;
# Extract the important fields from the file
# Status:
my $status = "";
if ($jobstatusdata =~ m!^\s*status\s*\=\s*{([^{}]*)}\s*$!m) {
$status = $1;
}
# Omit this job when it is already finished, cancelled, or aborted
# (then it cannot be killed any more)
next if (($status eq "") || ($status =~ m!aborted!) ||
($status =~ m!finished!) || ($status =~ m!cancelled!));
# Printer
my $printer;
if ($jobstatusdata =~ m!^\s*printer\s*\=\s*{([^{}]*)}\s*$!m) {
$printer = $1;
}
# Omit this job when we want to remove jobs on another printer
next if ((!(defined($opt_a))) && ($printer ne $config->{'queue'}));
# Owner
my $owner;
if ($jobstatusdata =~
m!^\s*env_driver\s*\=\s*{.*\"LOGNAME\"\s*=\s*\"([^\"]*)\".*}\s*$!m) {
$owner = $1;
}
# Kill the job when it is in the scope of jobs defined by the
# command line
if ((($nojob == 0) && (defined($joblist->{$jobnumbers[$i]}))) ||
(($nouser == 0) && (defined($userlist->{$owner}))) ||
(($opt_alljobs == 1) && ($ENV{'LOGNAME'} eq $owner)) ||
(($opt_alljobs == 1) && ($ENV{'LOGNAME'} eq "root")) ||
(($mostrecent == 1) && ($nojob == 1) && ($nouser == 1) &&
($opt_alljobs == 0))) {
system("touch $ENV{'HOME'}/.printjobs/$jobnumbers[$i].cancelled; chmod 0600 $ENV{'HOME'}/.printjobs/$jobnumbers[$i].cancelled");
print STDERR "Cancel request for job $jobnumbers[$i] submitted!\n";
$nothingremoved = 0;
}
$mostrecent = 0;
}
# Say "No cancel request sent" if no job was killed
if ($nothingremoved == 1) {
print STDERR "no cancel request sent\n";
}
}
sub control_pdq {
# PDQ does not have functionality for enabling/disabling queues,
# holding/releasing/moving jobs, etc.
die "Advanced queue/job manipulation functionality is not supported under PDQ!\n";
}
sub get_pdq_default_printer {
# Read the help message of PDQ
open PDQHELP, "pdq --help 2>&1 |";
$pdqhelp = join ("", <PDQHELP>);
close PDQHELP;
# Search the "default" line
if ($pdqhelp =~ m!default\s+printer.*\s+(\S+)\s*$!mg) {
return $1;
} else {
die "No default printer defined, you have to specify a printer with \"-P\" or \"-d\"!\n";
}
}
sub pdq_check_printer {
my $printer = $_[0];
# Read the help message of PDQ
open PDQHELP, "pdq --help 2>&1 |";
$pdqhelp = join ("", <PDQHELP>);
close PDQHELP;
# Search the appropriate printer entry
return ($pdqhelp =~ m!^\s+$printer\s+\-\s+.*\s+\-\s*$!mg);
}
sub detect_spooler {
# If tcp/localhost:631 opens, cups
my $page = $db->getpage('http://localhost:631/', 1);
if ($page =~ m!Common UNIX Printing System!) {
return 'cups';
}
# Else if /etc/printcap, some sort of lpd thing
if (-f $sysdeps->{'lpd-pcap'}) {
# If -f /etc/lpd.conf, lprng
if (-f $sysdeps->{'lprng-conf'}) {
return 'lprng';
} elsif (-x $sysdeps->{'lpd-bin'}) {
# There's a /usr/sbin/lpd
return 'lpd';
}
}
# pdq executable in our path somewhere?
for (split(':', $ENV{'PATH'})) {
if (-x "$_/pdq") {
return 'pdq';
}
}
return undef;
}
sub unimp {
die "Sorry, $action for your spooler is unimplemented...\n";
}
sub help {
my $action = 'all';
# Set up the help message depending on how we were called
if ($progname =~ m!^lpc!) { # 'lpc*' ==> control
$action = 'control';
print STDERR <<EOF;
Usage: $progname [ -s spooler ] [ -i ] command [ arguments ]
or $progname -h
EOF
} elsif ($progname =~ m!^lprm!) { # 'lprm*' ==> remove jobs
$action = 'remove';
print STDERR <<EOF;
Usage: $progname [ -s spooler ] [ -P queuename ] [ - ] [ -i ] [ jobid1 jobid2 ... ]
or $progname -h
EOF
} elsif ($progname =~ m!^lpq!) { # 'lpq*' ==> list jobs
$action = 'query';
print STDERR <<EOF;
Usage: $progname [ -s spooler ] [ -P queuename ] [ -i ] [ -a ] [ user1 user2 ... ]
or $progname -h
EOF
} elsif (($progname =~ m!^lpr!) || ($progname =~ m!^lp!)) { # 'lpr*', 'lp*' ==> print
$action = 'print';
print STDERR <<EOF;
Usage: $progname [ -s spooler ] [ -P queuename ] \
[ -o option1=value1 -o option2 ... ] [ -i ] [ file1 file2 ... ]
or $progname -S [ -s spooler ] [ -i ]
or $progname -h [ -s spooler ] [ -P queuename ] [ -i ]
EOF
} else { # name does not determine the action
print STDERR <<EOF;
Usage: $progname [ -s spooler ] [ -P queuename ] \
[ -o option1=value1 -o option2 ... ] [ -i ] \
[ file1 file2 ... ]
or $progname -Q [ -s spooler ] [ -P queuename ] [ -i ] [ -a ] \
[ user1 user2 ... ]
or $progname -R [ -s spooler ] [ -P queuename ] [ - ] [ -i ] \
[ jobid1 jobid2 ... ]
or $progname -C [ -s spooler ] [ -i ] command [ arguments ]
or $progname -S [ -s spooler ] [ -i ]
or $progname -h [ -s spooler ] [ -P queuename ] [ -i ]
EOF
}
print STDERR <<EOF;
-s spooler Explicit spooler type (cups,lpd,lprng,pdq)
EOF
if ($action ne 'control') {
print STDERR <<EOF;
-P queuename Command should apply to this queue
EOF
}
if (($action eq 'print') || ($action eq 'all')) {
print STDERR <<EOF;
-o option=value Set option to value
-o option Set the switch option
-\# n Print n copies
file1 file2 ... Files to be printed, when no file is given, standard input
will be printed
EOF
}
if ($action eq 'all') {
print STDERR <<EOF;
-Q Query the jobs in a queue
EOF
}
if (($action eq 'query') || ($action eq 'all')) {
print STDERR <<EOF;
-a Query the jobs in all queues
user1 user2 ... Users whose jobs should be listed
EOF
}
if ($action eq 'all') {
print STDERR <<EOF;
-R Remove a job from a queue
EOF
}
if (($action eq 'remove') || ($action eq 'all')) {
print STDERR <<EOF;
- Remove all your jobs
jobid1 jobid2 IDs of the jobs to be removed
EOF
}
if ($action eq 'all') {
print STDERR <<EOF;
-C Execute control commands for queue/job manipulation
EOF
}
if (($action eq 'control') || ($action eq 'all')) {
print STDERR <<EOF;
command [ arguments ] Control command for queue/job manipulation. The
commands are the ones of the BSD "lpc" utility. Use
the control command "help" to get a list of supported
commands. Note: the amount of commands varies with the
spooler, but the same commands given under different
spoolers do the same thing.
EOF
}
print STDERR <<EOF;
-i Interactive mode: You will be asked if $progname
is in doubt about something. Otherwise $progname
uses auto-detection or quits with an error.
EOF
if (($action eq 'print') || ($action eq 'all')) {
print STDERR <<EOF;
-S Save the chosen spooler as the default spooler
-h Show this message or show a list of available options if a
queue is specified
EOF
} else {
print STDERR <<EOF;
-h Show this message
EOF
}
exit 0;
}
# Help on printer-specific options
sub help_options {
my ($config) = $_[0];
# Is there an easier way to do this?
eval `foomatic-configure -P -n $config->{'queue'} -s $config->{'spooler'}`;
print "Available options for queue $config->{'queue'}:\n";
foreach my $arg (@{$QUEUES[0]->{'args'}}) {
next if $arg->{'hidden'};
my @vals = ();
print " $arg->{'name'} : < ";
foreach my $val (@{$arg->{'vals'}}) {
push @vals, $val->{'value'};
}
print join(' | ', @vals) . " >\n";
}
exit 0;
}